﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.IO;
using System.Linq;
using OAuth.Net.Common;
using System.Runtime.Serialization.Formatters.Binary;
using OAuth.Net.Consumer;
using Rodunu.Movies.Contracts;
using Rodunu.Movies.Interfaces.User;
using Rodunu.Movies.Logic.User;
using Rodunu.Movies.Services.NetFlix.DataProvider.Logic;

namespace Rodunu.Movies.Services.NetFlix.DataProvider.NFService
{
    public class FileTokenStore : ITokenStore
    {
        private readonly NetflixDataLogic _netflixDataLogic;
        private readonly IUser _userLogic;
        #region ITokenStore Members

        public FileTokenStore()
        {
            _netflixDataLogic = new NetflixDataLogic();
            _userLogic = new UserLogic();
        }

        public TokenContainer SaveTokens(UserInfo userId, string netflixUserId, IToken requestToken, IToken accessToken)
        {
            //try
            //{
                UserInfo user = _userLogic.Find(userId.Id);
                IList<NetflixTokenStore> tokenStore = _netflixDataLogic.FindByBase("UserInfo", userId);
                TokenContainer tk = new TokenContainer();
                if (requestToken != null)
                {
                    if (GetTokenByType(tokenStore, TokenType.Request) == null && GetTokenByType(tokenStore, TokenType.Access) == null)
                    {
                        _netflixDataLogic.Create(ConvertToNetflixTokenStore(requestToken, user));
                        tk.RequestToken = requestToken;
                    }
                    else
                    {
                        NetflixTokenStore token = GetTokenByType(tokenStore, TokenType.Request);
                        if (token != null)
                        {
                            tk.RequestToken = ConvertToOAuthToken(token);
                        }
                        else
                        {
                            tk.RequestToken = requestToken;
                        }
                    }
                }

                if (accessToken != null)
                {
                    if (GetTokenByType(tokenStore, TokenType.Access) == null)
                    {
                        _netflixDataLogic.Create(ConvertToNetflixTokenStore(accessToken, user));
                        _netflixDataLogic.Delete(GetTokenByType(tokenStore, TokenType.Request));
                        if (string.IsNullOrEmpty(userId.NetflixId))
                        {
                            _userLogic.UpdateUserNetflixId(userId.Id, netflixUserId);
                        }
                    }
                }
                return tk;
            //}
            //catch
            //{
            //    return false;
            //}
        }

        public TokenContainer GetTokens(UserInfo userId)
        {
            TokenContainer tk = new TokenContainer();
            IList<NetflixTokenStore> tokenStore = _netflixDataLogic.FindByBase("UserInfo", userId);

            foreach (NetflixTokenStore store in tokenStore)
            {
                switch ((TokenType)store.Type)
                {
                    case TokenType.Request:
                        tk.RequestToken = ConvertToOAuthToken(store);
                        break;
                    case TokenType.Access:
                        tk.AccessToken = ConvertToOAuthToken(store);
                        break;
                }
            }

            tk.UserID = userId.NetflixId;
            return tk;
        }

        private NetflixTokenStore GetTokenByType(IEnumerable<NetflixTokenStore> token, TokenType type)
        {
            return (from t in token where (TokenType) t.Type == type select t).SingleOrDefault();
        }

        private NetflixTokenStore ConvertToNetflixTokenStore(IToken token, UserInfo user)
        {
            NetflixTokenStore tokenStore = new NetflixTokenStore();

            if (string.IsNullOrEmpty(token.ConsumerKey))
            {
                throw new Exception("Consumer key cannot be empty.");
            }

            if (string.IsNullOrEmpty(token.Secret))
            {
                throw new Exception("Secret cannot be empty.");
            }

            if (string.IsNullOrEmpty(token.Token))
            {
                throw new Exception("Token cannot be empty.");
            }

            tokenStore.ConsumerKey = token.ConsumerKey;
            tokenStore.Secret = token.Secret;
            tokenStore.Status = (int)token.Status;
            tokenStore.Token = token.Token;
            tokenStore.Type = (int)token.Type;
            tokenStore.UserInfo = user;

            return tokenStore;
        }

        private OAuthToken ConvertToOAuthToken(NetflixTokenStore store)
        {
            return new OAuthToken((TokenType) store.Type, store.Token, store.Secret, store.ConsumerKey)
                                   {Status = ((TokenStatus) store.Status)};
        }

        #endregion

        [Serializable]
        public class TokenContainer
        {
            public IToken RequestToken { get; set; }
            public IToken AccessToken { get; set; }
            public string UserID { get; set; }
        }
    }
}